/* 
 * File:   statement_execution.c
 * Author: lin
 *
 * Created on May 8, 2011, 11:23 AM
 */

#include <stdio.h>
#include <stdlib.h>
#include "runtime.h"
#include "backend.h"
#include "evaluation.c"
struct loop_execution {
    int prerun;

    struct expression *initialization;
    struct expression *condition;
    struct expression *iteration;

    int statement_count;
    struct statement *statements;
};

struct execution execute_statement_list
(int size, struct statement *statements, struct access_table *table, int context);

struct execution execute_expression_stmt
(struct expression *expression, struct access_table *table, int context);

struct execution execute_assign_stmt
(struct expression *left, struct expression *right, struct access_table *table, int context);

struct execution execute_if_else_stmt
(struct expression *condition,
        int true_size,
        struct statement *true_statements,
        int false_size,
        struct statement *false_statements,
        struct access_table *table,
        int context);

struct execution execute_loop_stmt
(struct loop_execution loop, struct access_table *table, int context);
/*
 *  statement_execution.c
 *
 *
 *  Created by Yi Lin on 11-5-7.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */



struct execution execute_event(struct event *e, int context) {

    printf("execute_event \n");
    struct access_table *table = NULL;

    struct execution ret = execute_statement_list
            (e->statement_count, e->statement_table, table, context);

    if (ret.cate != EXE_FINISHED) {
        return INVALID_EXECUTION;
    }

    return ret;
}

struct execution execute_statement_list
(int size, struct statement *statements, struct access_table *table, int context) {


    printf("execute statement list\n");
    struct execution ret;
    int i;
    for (i = 0; i < size; i++) {
        ret = execute_statement(&statements[i], table, context);

        // return statement in a function
        if (ret.cate == EXE_RETURN) {
            if (context == CONTEXT_FUNCTION) {
                return ret;
            } else {
                return INVALID_EXECUTION;
            }
        }

        if (ret.cate == EXE_BREAK) {

            if (context == CONTEXT_LOOP) {
                return ret;
            } else {
                return INVALID_EXECUTION;
            }
        }

    }

    ret.cate = EXE_FINISHED;
    return ret;
}



struct execution execute_statement
(struct statement *stmt, struct access_table *table, int context) {

    struct loop_execution loop;
    struct execution ret;
    
    switch (stmt->cate) {
        case EXPRESSION:
            return execute_expression_stmt(stmt->spec.s_expression.expression, table, context);

        case IF:
            return execute_if_else_stmt
                    (stmt->spec.s_if.condition,
                    stmt->spec.s_if.statement_count,
                    stmt->spec.s_if.statement_table,
                    0, NULL, table, context);

        case IF_ELSE:
            return execute_if_else_stmt
                    (stmt->spec.s_if_else.condition,
                    stmt->spec.s_if_else.truestatement_count,
                    stmt->spec.s_if_else.truestatement_table,
                    stmt->spec.s_if_else.falsestatement_count,
                    stmt->spec.s_if_else.falsestatement_table,
                    table, context);
        case WHILE:
           
            loop.prerun = 0;
            loop.initialization = NULL;
            loop.condition = stmt->spec.s_while.condition;
            loop.statement_count = stmt->spec.s_while.statement_count;
            loop.statements = stmt->spec.s_while.statement_table;
            loop.iteration = NULL;

            return execute_loop_stmt(loop, table, context);

        case DO_WHILE:
            loop.prerun = 1;
            loop.initialization = NULL;
            loop.condition = stmt->spec.s_do_while.condition;
            loop.statement_count = stmt->spec.s_do_while.statement_count;
            loop.statements = stmt->spec.s_do_while.statement_table;
            loop.iteration = NULL;
            
            return execute_loop_stmt(loop, table, context);

        case FOR:

            loop.prerun = 0;
            loop.initialization = stmt->spec.s_for.initialization;
            loop.condition = stmt->spec.s_for.condition;
            loop.statement_count = stmt->spec.s_for.statement_count;
            loop.statements = stmt->spec.s_for.statement_table;
            loop.iteration = stmt->spec.s_for.iteration;
            
            return execute_loop_stmt(loop, table, context);

        case BREAK:
            ret.cate = EXE_BREAK;
            return ret;

        default:
            return INVALID_EXECUTION;
    }

}

struct execution execute_expression_stmt
(struct expression *e, struct access_table *table, int context) {

    printf("execute expression\n");
    switch (e->cate) {
        case ASSIGN:
            return execute_assign_stmt(e->spec.assign.first,
                    e->spec.assign.second, table, context);
        default:
            return INVALID_EXECUTION;

    }

}

struct execution execute_assign_stmt
(struct expression *left, struct expression *right, struct access_table *table, int context) {

    printf("execute assign statement\n");

    struct execution ret_execution;

    struct evaluation left_evaluation = evaluate_expression(left, table, context);
    struct evaluation right_evaluation = evaluate_expression(right, table, context);

    if (left_evaluation.cate != VARIABLE) {
        printf("invalid_execution");
        return INVALID_EXECUTION;
    }


    switch (left_evaluation.spec._variable._type.cate) {
        case INTEGER:
        case BOOLEAN:
            printf("assigning new value %d\n", evaluation_value(right_evaluation, context));
            (*left_evaluation.spec._variable.spec.value)
                    = evaluation_value(right_evaluation, context);
            break;

        default:
            return INVALID_EXECUTION;
    }

    ret_execution.cate = EXE_FINISHED;
    ret_execution.evaluation = left_evaluation;

    return ret_execution;
}

struct execution execute_if_else_stmt
(struct expression *condition,
        int true_size,
        struct statement *true_statements,
        int false_size,
        struct statement *false_statements,
        struct access_table *table,
        int context) {

    printf("executing if-else stmt\n");

    struct evaluation cond_evaluation
            = evaluate_expression(condition, table, context);
    int cond_value = evaluation_value(cond_evaluation, context);

    if (cond_value)
        return execute_statement_list(true_size, true_statements, table, context);

    else if (false_size > 0 && false_statements != NULL)
        return execute_statement_list(false_size, false_statements, table, context);

    return INVALID_EXECUTION;

}

/* return expression; */
struct execution execute_return_stmt(struct x_expression *value) {
    return INVALID_EXECUTION;
}

struct execution execute_loop_stmt
(struct loop_execution loop, struct access_table *table, int context) {

    printf("execute loop\n");
    if (loop.condition == NULL)
        return INVALID_EXECUTION;

    struct execution stmt_ret;

    /* for "do while", prerun the statements*/
    if (loop.prerun == 1) {
        printf("prerun the loop\n");
        stmt_ret = execute_statement_list(loop.statement_count, loop.statements, table, context);

        if (stmt_ret.cate == EXE_ERROR) {
            return INVALID_EXECUTION;
        }
    }

    /* for "for", initialization */
    if (loop.initialization != NULL) {
        printf("initialize the loop\n");
        stmt_ret = execute_expression_stmt(loop.initialization, table, context);

        if (stmt_ret.cate == EXE_ERROR) {
            return INVALID_EXECUTION;
        }
    }

    while (1) {
        printf("in loop\n");
        struct evaluation condition =
            evaluate_expression(loop.condition, table, context);

        if (evaluation_value(condition, context) == 0) {
            printf(" loop off \n");
            break;
        } else {
            printf(" loop on \n");
        }

        stmt_ret = execute_statement_list(loop.statement_count,
                loop.statements, table, CONTEXT_LOOP);

        if (stmt_ret.cate == EXE_ERROR)
            return INVALID_EXECUTION;

        if (stmt_ret.cate == EXE_BREAK) {
            printf("loop break \n");
            break;
        }

        if (stmt_ret.cate == EXE_CONTINUE)
            continue;

        /* for "for", iteration*/
        if (loop.iteration != NULL) {
            stmt_ret = execute_expression_stmt(loop.iteration, table, context);
            if (stmt_ret.cate == EXE_ERROR)
                return INVALID_EXECUTION;
        }
    }

    stmt_ret.cate = EXE_FINISHED;
    return stmt_ret;


}